load("//bazel:tachyon.bzl", "if_gpu_is_configured")
load(
    "//bazel:tachyon_cc.bzl",
    "tachyon_cc_library",
    "tachyon_cc_unittest",
    "tachyon_cuda_test",
    "tachyon_cuda_unittest",
)

package(default_visibility = ["//visibility:public"])

tachyon_cc_library(
    name = "cubic_extension_field",
    hdrs = ["cubic_extension_field.h"],
    deps = [
        ":cyclotomic_multiplicative_subgroup",
        ":extension_field_base",
        "//tachyon/base/buffer:copyable",
        "//tachyon/base/json",
        "@com_google_absl//absl/strings",
        "@com_google_absl//absl/types:span",
    ],
)

tachyon_cc_library(
    name = "cyclotomic_multiplicative_subgroup",
    hdrs = ["cyclotomic_multiplicative_subgroup.h"],
    deps = [
        ":finite_field",
        "//tachyon/base:optional",
        "//tachyon/base/containers:adapters",
    ],
)

tachyon_cc_library(
    name = "extended_packed_field_traits_forward",
    hdrs = ["extended_packed_field_traits_forward.h"],
)

tachyon_cc_library(
    name = "extension_field_base",
    hdrs = ["extension_field_base.h"],
    deps = [
        ":extended_packed_field_traits_forward",
        ":extension_field_traits_forward",
        ":packed_field_traits_forward",
        "//tachyon/base/containers:container_util",
    ],
)

tachyon_cc_library(
    name = "extension_field_traits_forward",
    hdrs = ["extension_field_traits_forward.h"],
)

tachyon_cc_library(
    name = "finite_field",
    hdrs = ["finite_field.h"],
    deps = [
        ":finite_field_traits",
        "//tachyon/math/base:field",
        "//tachyon/math/finite_fields/square_root_algorithms",
    ],
)

tachyon_cc_library(
    name = "finite_field_forwards",
    hdrs = ["finite_field_forwards.h"],
)

tachyon_cc_library(
    name = "finite_field_traits",
    hdrs = ["finite_field_traits.h"],
    deps = [
        ":finite_field_forwards",
        "//tachyon/math/matrix:cost_calculator_forward",
        "@eigen_archive//:eigen3",
    ],
)

tachyon_cc_library(
    name = "fp2",
    hdrs = ["fp2.h"],
    deps = [
        ":extension_field_traits_forward",
        ":quadratic_extension_field",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "fp3",
    hdrs = ["fp3.h"],
    deps = [
        ":cubic_extension_field",
        ":extension_field_traits_forward",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "fp4",
    hdrs = ["fp4.h"],
    deps = [
        ":extension_field_traits_forward",
        ":quadratic_extension_field",
        ":quartic_extension_field",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "fp6",
    hdrs = ["fp6.h"],
    deps = [
        ":cubic_extension_field",
        ":extension_field_traits_forward",
        ":quadratic_extension_field",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "fp12",
    hdrs = ["fp12.h"],
    deps = [
        ":extension_field_traits_forward",
        ":quadratic_extension_field",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "legendre_symbol",
    hdrs = ["legendre_symbol.h"],
)

tachyon_cc_library(
    name = "modulus",
    hdrs = ["modulus.h"],
    deps = ["//tachyon/math/base:big_int"],
)

tachyon_cc_library(
    name = "packed_prime_field_base",
    hdrs = ["packed_prime_field_base.h"],
    deps = [
        ":packed_field_traits_forward",
        "//tachyon/base/containers:container_util",
        "//tachyon/base/functional:callback",
        "//tachyon/base/strings:string_util",
    ],
)

tachyon_cc_library(
    name = "packed_field_traits_forward",
    hdrs = ["packed_field_traits_forward.h"],
)

tachyon_cc_library(
    name = "packed_prime_field32_avx2",
    hdrs = ["packed_prime_field32_avx2.h"],
    deps = [
        "//tachyon/base:compiler_specific",
        "//tachyon/base/functional:callback",
    ],
)

tachyon_cc_library(
    name = "packed_prime_field32_avx512",
    hdrs = ["packed_prime_field32_avx512.h"],
    deps = ["//tachyon/base:compiler_specific"],
)

tachyon_cc_library(
    name = "packed_prime_field32_neon",
    hdrs = ["packed_prime_field32_neon.h"],
    deps = ["//tachyon/base:compiler_specific"],
)

tachyon_cc_library(
    name = "prime_field_base",
    hdrs = ["prime_field_base.h"],
    deps = [
        ":extension_field_traits_forward",
        ":finite_field",
        ":legendre_symbol",
        ":packed_field_traits_forward",
        ":prime_field_util",
        "//tachyon/base:bits",
        "//tachyon/base/json",
        "//tachyon/base/strings:string_number_conversions",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_absl//absl/hash",
    ],
)

tachyon_cc_library(
    name = "prime_field_conversions",
    hdrs = ["prime_field_conversions.h"],
    deps = [":finite_field_forwards"],
)

tachyon_cc_library(
    name = "prime_field_fallback",
    hdrs = ["prime_field_fallback.h"],
    deps = [
        ":prime_field_base",
        "//tachyon/base:compiler_specific",
        "//tachyon/base:logging",
        "//tachyon/base/containers:adapters",
        "//tachyon/base/strings:string_util",
        "//tachyon/math/base:arithmetics",
        "//tachyon/math/base:byinverter",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_absl//absl/base",
        "@com_google_googletest//:gtest_prod",
    ],
)

tachyon_cc_library(
    name = "prime_field_gpu",
    hdrs = ["prime_field_gpu.h"],
    deps = [
        ":finite_field_forwards",
        ":modulus",
        ":prime_field_base",
        "//tachyon/math/finite_fields/kernels:carry_chain",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "prime_field_gpu_debug",
    hdrs = [
        "carry_chain.h",
        "prime_field_gpu_debug.h",
        "prime_field_ops_internal.h",
    ],
    deps = [":finite_field_forwards"],
)

tachyon_cc_library(
    name = "prime_field_util",
    srcs = ["prime_field_util.cc"],
    hdrs = ["prime_field_util.h"],
    deps = [
        "//tachyon:export",
        "@local_config_gmp//:gmp",
    ],
)

tachyon_cc_library(
    name = "prime_field_x86",
    hdrs = ["prime_field_x86.h"],
    deps = [
        ":modulus",
        ":prime_field_base",
        "//tachyon/base:compiler_specific",
        "//tachyon/base:logging",
        "//tachyon/base/containers:adapters",
        "//tachyon/base/strings:string_util",
        "//tachyon/math/base:arithmetics",
        "//tachyon/math/base/gmp:gmp_util",
        "@com_google_googletest//:gtest_prod",
    ],
)

tachyon_cc_library(
    name = "quadratic_extension_field",
    hdrs = ["quadratic_extension_field.h"],
    deps = [
        ":cyclotomic_multiplicative_subgroup",
        ":extension_field_base",
        "//tachyon/base/buffer:copyable",
        "//tachyon/base/json",
        "@com_google_absl//absl/strings",
        "@com_google_absl//absl/types:span",
    ],
)

tachyon_cc_library(
    name = "quartic_extension_field",
    hdrs = ["quartic_extension_field.h"],
    deps = [
        ":cyclotomic_multiplicative_subgroup",
        ":extension_field_base",
        "//tachyon/base/buffer:copyable",
        "//tachyon/base/json",
        "@com_google_absl//absl/base",
        "@com_google_absl//absl/strings",
        "@com_google_absl//absl/types:span",
    ],
)

tachyon_cc_library(
    name = "small_prime_field",
    hdrs = ["small_prime_field.h"],
    deps = [
        ":prime_field_base",
        "//tachyon/base:logging",
        "//tachyon/base:random",
        "//tachyon/base/strings:string_number_conversions",
        "//tachyon/base/strings:string_util",
        "//tachyon/build:build_config",
        "//tachyon/math/base:egcd",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_library(
    name = "small_prime_field_mont",
    hdrs = ["small_prime_field_mont.h"],
    deps = [
        ":prime_field_base",
        "//tachyon/base:logging",
        "//tachyon/base:random",
        "//tachyon/base/strings:string_number_conversions",
        "//tachyon/base/strings:string_util",
        "//tachyon/build:build_config",
        "@com_google_absl//absl/base",
    ],
)

tachyon_cc_unittest(
    name = "finite_fields_unittests",
    srcs = [
        "cubic_extension_field_unittest.cc",
        "finite_field_unittest.cc",
        "fp12_unittest.cc",
        "fp2_unittest.cc",
        "fp6_unittest.cc",
        "modulus_unittest.cc",
        "prime_field_base_unittest.cc",
        "prime_field_generator_unittest.cc",
        "prime_field_unittest.cc",
        "quadratic_extension_field_unittest.cc",
        "quartic_extension_field_unittest.cc",
    ] + select({
        "@platforms//cpu:x86_64": ["packed_prime_field_unittest.cc"],
        "@platforms//cpu:aarch64": ["packed_prime_field_unittest.cc"],
        "//conditions:default": [],
    }),
    deps = [
        ":modulus",
        ":packed_field_traits_forward",
        ":prime_field_base",
        ":prime_field_gpu_debug",
        "//tachyon/base:auto_reset",
        "//tachyon/base:bits",
        "//tachyon/base:optional",
        "//tachyon/base/buffer:vector_buffer",
        "//tachyon/build:build_config",
        "//tachyon/math/elliptic_curves/bls12/bls12_381:fq",
        "//tachyon/math/elliptic_curves/bls12/bls12_381:fr",
        "//tachyon/math/elliptic_curves/bn/bn254:fq",
        "//tachyon/math/elliptic_curves/bn/bn254:fq12",
        "//tachyon/math/elliptic_curves/bn/bn254:fr",
        "//tachyon/math/elliptic_curves/pasta/pallas:fq",
        "//tachyon/math/elliptic_curves/pasta/pallas:fr",
        "//tachyon/math/elliptic_curves/pasta/vesta:fq",
        "//tachyon/math/elliptic_curves/pasta/vesta:fr",
        "//tachyon/math/elliptic_curves/secp/secp256k1:fq",
        "//tachyon/math/elliptic_curves/secp/secp256k1:fr",
        "//tachyon/math/finite_fields/baby_bear",
        "//tachyon/math/finite_fields/baby_bear:baby_bear4",
        "//tachyon/math/finite_fields/binary_fields",
        "//tachyon/math/finite_fields/goldilocks",
        "//tachyon/math/finite_fields/koala_bear",
        "//tachyon/math/finite_fields/mersenne31",
        "//tachyon/math/finite_fields/test:finite_field_test",
        "//tachyon/math/finite_fields/test:gf7",
        "//tachyon/math/finite_fields/test:gf7_2",
        "//tachyon/math/finite_fields/test:gf7_3",
        "@com_google_absl//absl/hash:hash_testing",
    ] + select({
        "@platforms//cpu:x86_64": [
            "//tachyon/math/finite_fields/baby_bear/internal:packed_baby_bear_avx2",
            "//tachyon/math/finite_fields/baby_bear/internal:packed_baby_bear_avx512",
            "//tachyon/math/finite_fields/koala_bear/internal:packed_koala_bear_avx2",
            "//tachyon/math/finite_fields/koala_bear/internal:packed_koala_bear_avx512",
            "//tachyon/math/finite_fields/mersenne31/internal:packed_mersenne31_avx2",
            "//tachyon/math/finite_fields/mersenne31/internal:packed_mersenne31_avx512",
        ],
        "@platforms//cpu:aarch64": [
            "//tachyon/math/finite_fields/baby_bear/internal:packed_baby_bear_neon",
            "//tachyon/math/finite_fields/koala_bear/internal:packed_koala_bear_neon",
            "//tachyon/math/finite_fields/mersenne31/internal:packed_mersenne31_neon",
        ],
        "//conditions:default": [],
    }),
)

tachyon_cuda_unittest(
    name = "finite_fields_gpu_unittests",
    srcs = if_gpu_is_configured(["prime_field_gpu_unittest.cc"]),
    deps = [
        ":prime_field_conversions",
        "//tachyon/device/gpu:gpu_memory",
        "//tachyon/math/finite_fields/kernels:prime_field_ops",
        "//tachyon/math/finite_fields/test:finite_field_test",
        "//tachyon/math/finite_fields/test:gf7",
        "//tachyon/math/finite_fields/test:gf7_gpu",
        "//tachyon/math/test:launch_op_macros",
    ],
)

tachyon_cuda_test(
    name = "finite_field_correctness_gpu_tests",
    size = "small",
    srcs = if_gpu_is_configured(["prime_field_correctness_gpu_test.cc"]),
    deps = [
        ":prime_field_conversions",
        "//tachyon/device/gpu:gpu_memory",
        "//tachyon/math/elliptic_curves/bn/bn254:fq",
        "//tachyon/math/elliptic_curves/bn/bn254:fq_gpu",
        "//tachyon/math/finite_fields/kernels:prime_field_ops",
        "//tachyon/math/finite_fields/test:finite_field_test",
        "//tachyon/math/test:launch_op_macros",
    ],
)
